package com.zjdiepu.www.security.sign.lang;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.zjdiepu.www.security.consts.SignConsts;
/**
 * 签名辅助工具类
 * 类描述:签名辅助工具类 <br/>     
 * 项目名称:zjdiepu-client <br/> 
 * 类名称:SignUtil <br/>     
 * 创建人:xiongxiaotun <br/> 
 * 创建时间:2017年8月23日 上午10:37:58  <br/>   
 * 修改人:xiongxiaotun <br/> 
 * 修改时间: 2017年8月23日 上午10:37:58   <br/>  
 * 修改备注:   <br/> 
 * @version V1.0   <br/>
 */
public class SignUtil {
	private static final SimpleDateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
	
	  /**
     * 返回待签名map
     *
     * @param map
     * @param param
     * @return
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
	public static Map<String, Object> getSignMap(Map<String, Object> map, Object param, Class<?> clazz, String signName) {
    	if(!ObjectUtils.allNotNull(param, clazz)) {
    		return map;
    	}
    	if(StringUtils.isBlank(signName)) {
    		return map;
    	}
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
				try {
					String fieldName = field.getName();
					String finalFieldName = fieldName;
					JSONField jsonField = field.getAnnotation(JSONField.class);
					if(null != jsonField) {
						finalFieldName = jsonField.name();
					}
					PropertyDescriptor pd = new PropertyDescriptor(fieldName, clazz);
					Method getMethod = pd.getReadMethod();//获得get方法
					Object o = getMethod.invoke(param);//执行get方法返回一个Object
					if (!signName.equals(fieldName) && !signName.equals(finalFieldName) && o != null && StringUtils.isNotBlank(o.toString())) {
						map.put(finalFieldName, JSON.toJSONString(o, SerializerFeature.SortField));//非空属性参与签名（字符串使用blank验证是否为空）
					}
				} catch (Exception e) {
					//不处理
				}
        }
        
        Class<?> superClazz = clazz.getSuperclass();
        if (Objects.equals(superClazz, Object.class)) {
            return map;
        }
        return getSignMap(map, param, superClazz, signName);
    }
	
	public static String sortMapToString(Map<String, Object> map, String signKey, String signCovenantKey) {
		Set<ComparatorKey> keys = order(map.keySet());
        StringBuilder sb = new StringBuilder();
        // key=xxxx
        sb.append(signCovenantKey);
        sb.append(SignConsts.EQUALITY_SYMBOL);
        sb.append(signKey);
        for (ComparatorKey key : keys) {
            Object val = map.get(key.getSourceValue());
            String value = convertToString(val);
            // key=xxxx&
            sb.append(SignConsts.SPLIT_STRING);
            // param_name=param_value
            sb.append(key.getCompatatorValue());
            sb.append(SignConsts.EQUALITY_SYMBOL);
            sb.append(value);
        }
        return sb.toString();
	}

	public static String convertToString(Object obj) {
        Class<?> clazz = obj.getClass();
        if (clazz.isArray()) {
            List<String> lists = new LinkedList<String>();
            for (Object cobj : (Object[]) obj) {
                lists.add(convertToString(cobj));
            }
            return stringJoin(",", lists);
        }
        if (clazz.isPrimitive() || isBaseDataType(clazz)) {
            return obj.toString();
        }
        if (Iterable.class.isAssignableFrom(clazz)) {
            List<String> lists = new LinkedList<String>();
            for (Object cobj : (Iterable<?>) obj) {
                lists.add(convertToString(cobj));
            }
            return stringJoin(",", lists);
        }
        if (clazz == java.sql.Date.class || clazz == Date.class || clazz == java.sql.Time.class) {
            return DATE_TIME_FORMAT.format(((Date) obj));
        }
        String jsonStr = JSON.toJSONString(obj);
        return jsonStr;
    }

	public static String stringJoin(String str, List<String> lists) {
        StringBuffer sb = new StringBuffer();
        for (String list : lists) {
            sb.append(list + str);
        }
        return sb.toString().substring(0, sb.toString().length() - 1);
    }

    /**
     * 判断一个类是否为基本数据类型。
     *
     * @param clazz 要判断的类。
     * @return true 表示为基本数据类型。
     */
	public static boolean isBaseDataType(Class<?> clazz) {
        return (clazz.equals(String.class) || clazz.equals(Integer.class) || clazz.equals(Byte.class)
                || clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Float.class)
                || clazz.equals(Character.class) || clazz.equals(Short.class) || clazz.equals(BigDecimal.class)
                || clazz.equals(BigInteger.class) || clazz.equals(Boolean.class) || clazz.isPrimitive());
    }

	public static Set<ComparatorKey> order(Set<String> keys) {
        TreeSet<ComparatorKey> set = new TreeSet<ComparatorKey>(new SecurityComparator<>());
        for (String key : keys) {
            ComparatorKey ck = new ComparatorKey(key.toLowerCase(), key);
            set.add(ck);
        }
        return set;
    }
}
